/**
 * $Revision: 1.0 $
 * $Author: Eric Yang $
 * $Date: Aug 8, 2009 12:03:56 AM $
 *
 * Author: Eric Yang
 * Date  : Aug 8, 2009 12:03:56 AM
 *
 */
package com.gooex.service.organization;

import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.FlushMode;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.orm.hibernate3.SessionFactoryUtils;
import org.c4j.encode.EncodeTools;
import org.c4j.io.StreamTools;
import org.c4j.system.web.container.Application;

import com.gooex.domain.organization.Area;
import com.gooex.domain.organization.Authority;
import com.gooex.domain.organization.AuthorizedObject;
import com.gooex.domain.organization.Group;
import com.gooex.domain.organization.Role;
import com.gooex.domain.organization.User;

/**
 * @author Eric Yang
 * @version 1.0
 */
public class AuthorityContext {

	public static AuthorityContext instance;

	private static final Log logger = LogFactory.getLog(AuthorityContext.class);

	private IUserManager userManager;

	private IAreaManager areaManager;

	private IGroupManager groupManager;

	private IRoleManager roleManager;

	private IAuthorityManager authorityManager;

	private SessionFactory sessionFactory;

	private static User superUser;

	private static Area superArea;

	private static Role superRole;

	private static Group superGroup;

	private static Set<AuthorizedObject> authorizedObjects = new HashSet<AuthorizedObject>();

	private static Set<Authority> systemAuthorities = new HashSet<Authority>();

	public static AuthorityContext getInstance() {
		if (instance == null) {
			instance = new AuthorityContext();
			instance.init();
		}
		return instance;
	}

	private void init() {
		userManager = (IUserManager) Application.getComponent("userManager");
		areaManager = (IAreaManager) Application.getComponent("areaManager");
		groupManager = (IGroupManager) Application.getComponent("groupManager");
		roleManager = (IRoleManager) Application.getComponent("roleManager");
		authorityManager = (IAuthorityManager) Application.getComponent("authorityManager");
		sessionFactory = (SessionFactory) Application.getComponent("sessionFactory");

		try {
			openSession();
			Properties properties = new Properties();
			try {
				properties.load(StreamTools.getConfigureAsStream("authority.conf"));
			} catch (IOException e) {
				logger.error(e.getMessage(), e);
			}

			String areaName = (String) properties.get("super_area");
			String groupName = (String) properties.get("super_group");
			String roleName = (String) properties.get("super_role");
			String userName = (String) properties.get("super_user");
			String userPassword = (String) properties.get("super_user_password");
			String userEmail = (String) properties.get("super_user_email");

			List<Area> areas = areaManager.getAreas();

			if (areas != null && areas.size() > 0) {
				for (Area area : areas) {
					if (area.getName().equals(areaName)) {
						superArea = area;
						break;
					}
				}

				List<Group> groups = groupManager.getGroups();
				for (Group group : groups) {
					if (group.getName().equals(groupName)) {
						superGroup = group;
						break;
					}
				}
				List<Role> roles = roleManager.getRoles();
				for (Role role : roles) {
					if (role.getName().equals(roleName)) {
						superRole = role;
						break;
					}
				}

				List<User> users = userManager.getUsers();
				for (User user : users) {
					if (user.getName().equals(userName)) {
						superUser = user;
						break;
					}
				}

				List<Authority> authorities = superArea.getAuthorities();
				for (Authority authority : authorities) {
					systemAuthorities.add(authority);
				}
			}
			/* initial */
			else {
				Set<Object> keySet = properties.keySet();
				for (Iterator<Object> iterator = keySet.iterator(); iterator.hasNext();) {
					String item = (String) iterator.next();
					if (item.startsWith("authority_")) {
						Authority authority = new Authority();
						authority.setName(item);
						authority.setValue(properties.getProperty(item));
						authorityManager.saveAuthority(authority);
						systemAuthorities.add(authority);
					}
				}

				superArea = new Area();
				superGroup = new Group();
				superRole = new Role();
				superUser = new User();

				superArea.getAuthorities().addAll(systemAuthorities);
				superGroup.getAuthorities().addAll(systemAuthorities);
				superRole.getAuthorities().addAll(systemAuthorities);

				superArea.setName(areaName);
				superGroup.setName(groupName);
				superRole.setName(roleName);
				superUser.setName(userName);
				superUser.setPassword(EncodeTools.hash(userPassword));
				superUser.setEmail(userEmail);

				areaManager.saveArea(superArea);
				groupManager.saveGroup(superGroup);
				roleManager.saveRole(superRole);
				userManager.saveUser(superUser);

				superArea.addGroup(superGroup);
				superGroup.addRole(superRole);
				superRole.addUser(superUser);

				areaManager.saveArea(superArea);
				groupManager.saveGroup(superGroup);
				roleManager.saveRole(superRole);
				userManager.saveUser(superUser);
			}

			authorizedObjects.add(superArea);
			authorizedObjects.add(superGroup);
			authorizedObjects.add(superRole);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		} finally {
			closeSession();
		}
	}

	public static boolean isSystemObject(Object object) {
		if (object == null)
			return false;
		if (object instanceof AuthorizedObject)
			return getInstance().authorityManager.isSystemAuthorizedObject((AuthorizedObject) object);
		else if (object instanceof Authority)
			return getInstance().authorityManager.isSystemAuthority((Authority) object);
		else
			return false;
	}

	public static boolean isSystemUser(User user) {
		return isSystemObject(user.getRole());
	}

	private void openSession() {
		Session session = SessionFactoryUtils.getSession(sessionFactory, true);
		session.setFlushMode(FlushMode.AUTO);
		//TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));
	}

	private void closeSession() {
		//SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
		//SessionFactoryUtils.releaseSession(sessionHolder.getSession(), sessionFactory);
	}

	public static User getSuperUser() {
		getInstance();
		return superUser;
	}

	public static Area getSuperArea() {
		getInstance();
		return superArea;
	}

	public static Role getSuperRole() {
		getInstance();
		return superRole;
	}

	public static Group getSuperGroup() {
		getInstance();
		return superGroup;
	}

	public static Set<Authority> getSystemAuthorities() {
		getInstance();
		return systemAuthorities;
	}

	public static Set<AuthorizedObject> getSystemAuthorizedObjects() {
		getInstance();
		return authorizedObjects;
	}

}
